#include <slothttpd/stage/send_headers.hpp>
#include <slothttpd/http/response.hpp>
#include <slothttpd/http/status.hpp>
#include <slothttpd/connection.hpp>
#include <slothttpd/logger.hpp>
#include <slothttpd/http/http.hpp>

#include <cstring>

#include <limits.h>

#include <algorithm>

namespace slothttpd {
namespace stage {

send_headers::send_headers(connection_ptr conn, const char *path, config::file_location &conf,
                           boost::function<void()> on_complete) :
    ref_counted(conn),
    on_complete_(on_complete)
{
    file::open_result r;
    
    if (conf.async_send) {
        r = file::get_direct_io(c->pool, path, responce_file);
    } else if (conf.send_file_cache_fd) {
        r = file::get_cached(path, responce_file);
    } else {
        r = file::get_nocache(c->pool, path, responce_file);
    }
    
    if (r == file::success) {
        using boost::asio::buffer;
        
        http::response &response = c->responce;
        
        char *p = static_cast<char*>(c->pool.allocate(20));
        
        // TODO: remove magic number
        std::snprintf(p, 20, "%lld\r\n", (long long) responce_file->size());
        
        response.status_line(http::status::ok.status_line);
        response.push_back(boost::asio::buffer(http::headers::response::content_length));
        response.push_back(boost::asio::buffer(p, std::strlen(p)));
        for (auto b : conf.header_buffers) {
            response.push_back(b);
        }
        response.push_back(boost::asio::buffer(http::crlf));
        
        c->post_write_responce(boost::bind(&send_headers::handle_send_headers,
                                           send_headers_static_ptr(this),
                                           boost::asio::placeholders::error));
    } else if (r == file::not_found) {
        c->send_stock_response(http::status::not_found);
    } else if (r == file::forbidden) {
        c->send_stock_response(http::status::forbidden);
    } else {
        c->send_stock_response(http::status::internal_server_error);
    }
}

void send_headers::handle_send_headers(send_headers_static_ptr r, const boost::system::error_code &err)
{
    if (!err) {
        r->on_complete_();
        r->on_complete_ = boost::function<void()>();
    } else {
        logger() << err.message() << std::endl;
        r->c->close();
    }
}

}
}
